﻿using DA.AnimGraph;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine.UIElements;

namespace DA.AnimGraph.Editor {

    [NodeMenuItem(typeof(AGANode_StateMachine), "State Machine")]
    internal class NodeView_StateMachine : NodeViewBase {
        public override string titleText => "State Machine";
        protected override NodeViewInspectorSourceBase dataSource => inspectorData;
        NodeViewInspector_StateMachine inspectorData;
        internal override void Init(AGAHandle_Node handle, AnimGraphView graphView, AGEEnvironment ageContext) {
            inspectorData = new NodeViewInspector_StateMachine();
            inspectorData.SetHandle(handle);
            base.Init(handle, graphView, ageContext);
        }
    }

    internal class NodeViewInspector_StateMachine : NodeViewInspectorSourceBase {

        [InspectorField(label: "初始状态序号")] public AGAFieldModel_IntLink defaultState;
        [InspectorField(tag: "inputPort", isList: true)]
        public List<AGAFieldModel_InputPort> inputPort;
        [InspectorField(tag: "anyTransitions", label: "任意起始状态的过渡", isList: true)]
        public List<AGAFieldModel_SMTransition> anyTransitions; // 任意状态过渡，从transitions筛选出

        private List<AGAFieldModel_SMTransition> transitions;

        protected override void LoadFromModel() {
            var model = handleKeeper.handle.data.modelProperty as AGANodeModel_StateMachine;
            defaultState = model.defaultState;
            transitions = model.transitions;

            // inputPort
            var bNode = handleKeeper.handle.data as AGANode_BlendBase;
            int childrenCount = bNode.inputChildren.Count;
            inputPort = new List<AGAFieldModel_InputPort>(childrenCount);
            for (int i = 0; i < childrenCount; i++) {
                inputPort.Add(new AGAFieldModel_InputPort(bNode.inputNames[i], bNode.inputChildren[i]));
            }
        }
        protected override void SaveToModel() {
            // handleKeeper.handle.ModifyModel(m => {
            //     var model = m as AGANodeModel_StateMachine;
            //
            // });

            // 全量覆盖保存输入端口
            var newInputs = inputPort.Select(m => (m.portUuid, m.name)).ToList();
            handleKeeper.handle.WriteAllInput(newInputs);

            if (inspectorWidgets.ContainsKey("inputPort")) {
                var listView = inspectorWidgets["inputPort"] as ListViewAGE;
                listView.Rebuild();
            }

            if (inspectorWidgets.ContainsKey("anyTransitions")) {
                var listView2 = inspectorWidgets["anyTransitions"] as ListViewAGE;
                listView2.Rebuild();
            }

        }
        protected override VisualElement CustomizeField(string name, InspectorFieldAttribute fieldAttribute, FieldInfo fieldInfo, AGEContext ageContext, Action inspectorChangeCallback) {
            if (fieldAttribute.tag == "inputPort") {
                return BuildInputPortList(name, fieldAttribute, fieldInfo, ageContext, inspectorChangeCallback);
            }
            if (fieldAttribute.tag == "anyTransitions") {
                return BuildAnyTransitions(name, fieldAttribute, fieldInfo, ageContext, inspectorChangeCallback);
            }
            return base.CustomizeField(name, fieldAttribute, fieldInfo, ageContext, inspectorChangeCallback);
        }
        VisualElement BuildInputPortList(string name, InspectorFieldAttribute fieldAttribute, FieldInfo fieldInfo, AGEContext ageContext, Action inspectorChangeCallback) {
            var listView = new ListViewAGE() {
                title = name,
                enableCountController = true,
                itemsSource = inputPort,
            };
            listView.makeItem = () => {
                var w = new FoldoutWrapper();
                w.upButtonClicked += (index) => {
                    (inputPort[index], inputPort[index - 1]) = (inputPort[index - 1], inputPort[index]);
                    inspectorChangeCallback?.Invoke(); // 这里已经执行了 listView.Rebuild()
                };
                w.downButtonClicked += (index) => {
                    (inputPort[index], inputPort[index + 1]) = (inputPort[index + 1], inputPort[index]);
                    inspectorChangeCallback?.Invoke(); // 这里已经执行了 listView.Rebuild()
                };
                w.deleteButtonClicked += (index) => {
                    inputPort.RemoveAt(index);
                    inspectorChangeCallback?.Invoke(); // 这里已经执行了 listView.Rebuild()
                };
                var l = new InspectorField_SMPort(inputPort, transitions, ageContext, inspectorChangeCallback);
                return (l, w);
            };
            listView.bindItem = (element, wrapper, index) => {
                VisualElement nameInputField = null;
                if (element is InspectorField_SMPort field) {
                    field.portField.Init(null, inputPort[index], ageContext, inspectorChangeCallback);
                    nameInputField = field.portField;
                    field.Init(inputPort[index].portUuid);
                }
                if (wrapper is FoldoutWrapper w) {
                    w.index = index;
                    w.text = $"[{index}]";
                    w.enableUp = index > 0;
                    w.enableDown = index < inputPort.Count - 1;
                    w.enableDelete = inputPort.Count > 2;
                    w.SetToTitle(nameInputField);
                }
            };
            listView.addButtonClicked = () => {
                inputPort.Add(new AGAFieldModel_InputPort("new state"));
                inspectorChangeCallback?.Invoke(); // 这里已经执行了 listView.Rebuild()
            };
            return listView;
        }
        private VisualElement BuildAnyTransitions(string name, InspectorFieldAttribute fieldAttribute, FieldInfo fieldInfo, AGEContext ageContext1, Action inspectorChangeCallback) {
            // 筛选 anyTransitions
            anyTransitions = transitions.Where(p => p.sourceState == default).ToList();

            void OnAnyTransitionsModify() {
                // anyTransitions 中的条目重新加到 transitionList 中去
                for (int i = 0; i < anyTransitions.Count; i++) {
                    var index = transitions.FindIndex(p => p.uuid == anyTransitions[i].uuid);
                    if (index >= 0) {
                        transitions[index] = anyTransitions[i];
                    } else {
                        transitions.Add(anyTransitions[i]);
                    }
                }
                inspectorChangeCallback?.Invoke();
            }

            var listView = new ListViewAGE() {
                title = name,
                enableCountController = true,
                itemsSource = anyTransitions,
            };
            listView.makeItem = () => {
                var w = new FoldoutWrapper();
                w.upButtonClicked += (index) => {
                    (anyTransitions[index], anyTransitions[index - 1]) = (anyTransitions[index - 1], anyTransitions[index]);
                    inspectorChangeCallback?.Invoke(); // 这里已经执行了 listView.Rebuild()
                };
                w.downButtonClicked += (index) => {
                    (anyTransitions[index], anyTransitions[index + 1]) = (anyTransitions[index + 1], anyTransitions[index]);
                    inspectorChangeCallback?.Invoke(); // 这里已经执行了 listView.Rebuild()
                };
                w.deleteButtonClicked += (index) => {
                    var deletedEle = anyTransitions[index];
                    var uuid2Delete = deletedEle.uuid;
                    anyTransitions.RemoveAt(index);
                    var index2delete = transitions.FindIndex(p => p.uuid == uuid2Delete);
                    transitions.RemoveAt(index2delete);
                    OnAnyTransitionsModify();
                };
                var l = new InspectorField_SMTransition(inputPort);
                return (l, w);
            };
            listView.bindItem = (element, wrapper, index) => {
                if (element is InspectorField_SMTransition field) {
                    field.Init(null, anyTransitions[index], ageContext, OnAnyTransitionsModify);
                }
                if (wrapper is FoldoutWrapper w) {
                    w.index = index;
                    w.text = $"[{index}]";
                    w.enableDelete = true;
                }
            };
            listView.addButtonClicked = () => {
                var newTrans = new AGAFieldModel_SMTransition() {
                    sourceState = default,
                };
                anyTransitions.Add(newTrans);
                OnAnyTransitionsModify();
            };
            return listView;
        }


        class InspectorField_SMPort : VisualElement {
            public InspectorField_InputPort portField; // 这部分不再显示在foldout下，而是在标题上，这里只是持有对象而不添加到显示

            private List<AGAFieldModel_InputPort> inputPort; //用于查询
            private List<AGAFieldModel_SMTransition> transitionList; //用于查询
            private readonly AGEContext ageContext;
            private Action inspectorChangeCallback;
            private AUID selfState;
            private List<AGAFieldModel_SMTransition> filteredList;

            private ListViewAGE transitionListView;

            public InspectorField_SMPort(List<AGAFieldModel_InputPort> inputPort, List<AGAFieldModel_SMTransition> transitionList, AGEContext ageContext, Action inspectorChangeCallback) {
                this.inputPort = inputPort;
                this.transitionList = transitionList;
                this.ageContext = ageContext;
                this.inspectorChangeCallback = inspectorChangeCallback;

                portField = new() {
                    name = "name-field",
                    style = { flexGrow = 1, }
                };
            }

            public void Init(AUID selfState) {
                this.selfState = selfState;
                Clear();
                BuildUI();
            }

            protected void BuildUI() {
                // 过滤列表
                filteredList = transitionList.Where(p => p.sourceState == selfState).ToList();
                BuildListView();
                Add(transitionListView);
            }

            void OnModify() {
                // filteredList 中的条目重新加到 transitionList 中去
                for (int i = 0; i < filteredList.Count; i++) {
                    var index = transitionList.FindIndex(p => p.uuid == filteredList[i].uuid);
                    if (index >= 0) {
                        transitionList[index] = filteredList[i];
                    } else {
                        transitionList.Add(filteredList[i]);
                    }
                }
                inspectorChangeCallback?.Invoke();
            }

            void BuildListView() {
                transitionListView = new ListViewAGE() {
                    title = "过渡",
                    enableCountController = true,
                    itemsSource = filteredList,
                };
                transitionListView.makeItem = () => {
                    var w = new FoldoutWrapper();
                    w.upButtonClicked += (index) => {
                        (filteredList[index], filteredList[index - 1]) = (filteredList[index - 1], filteredList[index]);
                        inspectorChangeCallback?.Invoke(); // 这里已经执行了 listView.Rebuild()
                    };
                    w.downButtonClicked += (index) => {
                        (filteredList[index], filteredList[index + 1]) = (filteredList[index + 1], filteredList[index]);
                        inspectorChangeCallback?.Invoke(); // 这里已经执行了 listView.Rebuild()
                    };
                    w.deleteButtonClicked += (index) => {
                        var deletedEle = filteredList[index];
                        var uuid2Delete = deletedEle.uuid;
                        filteredList.RemoveAt(index); // 反正重新刷新，不用特意删？要的，不然还会加回去
                        var index2delete = transitionList.FindIndex(p => p.uuid == uuid2Delete);
                        transitionList.RemoveAt(index2delete);
                        OnModify();
                    };
                    var l = new InspectorField_SMTransition(inputPort);
                    return (l, w);
                };
                transitionListView.bindItem = (element, wrapper, index) => {
                    if (element is InspectorField_SMTransition field) {
                        field.Init(null, filteredList[index], ageContext, OnModify);
                    }
                    if (wrapper is FoldoutWrapper w) {
                        w.index = index;
                        w.text = $"[{index}]";
                        // w.enableUp = index > 0;
                        // w.enableDown = index < filteredList.Count - 1;
                        w.enableDelete = true;
                        // w.SetToTitle(nameInputField);
                    }
                };
                transitionListView.addButtonClicked = () => {
                    var newTrans = new AGAFieldModel_SMTransition() {
                        sourceState = selfState,
                    };
                    filteredList.Add(newTrans);
                    OnModify();
                };
            }
        }

        class InspectorField_SMTransition : InspectorField<AGAFieldModel_SMTransition> {
            List<AGAFieldModel_InputPort> inputPort; //用于查询

            private PopupField<AGAFieldModel_InputPort> targetField;
            private FloatField durationField;
            private ListViewAGE conditionListView;

            public InspectorField_SMTransition(List<AGAFieldModel_InputPort> inputPort) {
                this.inputPort = inputPort;
            }

            protected override void BuildUI() {
                targetField = new PopupField<AGAFieldModel_InputPort>("目标状态");
                targetField.RegisterValueChangedCallback(evt => OnModify());

                durationField = new FloatField("过渡时间");
                durationField.RegisterValueChangedCallback(evt => OnModify());
                durationField.value = source.duration;

                conditionListView = new ListViewAGE() {
                    title = "过渡条件（与）",
                    enableCountController = true,
                    itemsSource = source.conditions,
                };
                conditionListView.makeItem = () => {
                    var w = new FoldoutWrapper();
                    w.upButtonClicked += (index) => {
                        (source.conditions[index], source.conditions[index - 1]) = (source.conditions[index - 1], source.conditions[index]);
                        inspectorChangeCallback?.Invoke(); // 这里已经执行了 listView.Rebuild()
                    };
                    w.downButtonClicked += (index) => {
                        (source.conditions[index], source.conditions[index + 1]) = (source.conditions[index + 1], source.conditions[index]);
                        inspectorChangeCallback?.Invoke(); // 这里已经执行了 listView.Rebuild()
                    };
                    w.deleteButtonClicked += (index) => {
                        source.conditions.RemoveAt(index);
                        inspectorChangeCallback?.Invoke();
                    };
                    var l = new InspectorField_SMCondition();
                    return (l, w);
                };
                conditionListView.bindItem = (element, wrapper, index) => {
                    if (element is InspectorField_SMCondition field) {
                        field.Init(null, source.conditions[index], ageContext, inspectorChangeCallback);
                    }
                    if (wrapper is FoldoutWrapper w) {
                        w.index = index;
                        w.text = $"[{index}]";
                        w.enableUp = index > 0;
                        w.enableDown = index < source.conditions.Count - 1;
                        w.enableDelete = source.conditions.Count > 1;
                    }
                };
                conditionListView.addButtonClicked = () => {
                    var newCond = new AGAFieldModel_SMTransition.TransitionCondition();
                    source.conditions.Add(newCond);
                    inspectorChangeCallback?.Invoke();
                };
            }
            private void OnModify(bool skipCallback = false) {
                source.targetState = targetField.value.portUuid;
                source.duration = durationField.value;

                if (!skipCallback) {
                    inspectorChangeCallback?.Invoke();
                }
            }

            protected override void DrawUI() {
                var targetChoices = inputPort.Where(p => p.portUuid != source.sourceState).ToList();

                var targetIndex = targetChoices.FindIndex(p => p.portUuid == source.targetState);
                if (targetIndex == -1) {
                    targetIndex = 0;
                }
                targetField.choices = targetChoices;
                targetField.index = targetIndex;
                targetField.formatListItemCallback = p => p?.name; // 决定每个选项的文本
                targetField.formatSelectedValueCallback = p => p?.name; // 决定显示在下拉框中的文本
                Add(targetField);
                Add(durationField);
                Add(conditionListView);
                OnModify(true);
            }
        }

        class InspectorField_SMCondition : InspectorField<AGAFieldModel_SMTransition.TransitionCondition> {

            private EnumField conditionTypeField;
            private FloatField exitTimeField;

            private EnumField paramTypeField;
            private PopupField<AGA_Blackboard.Entry> paramField;
            private EnumField compareOperatorField;
            private EnumField compareParamSourceField;
            private PopupField<AGA_Blackboard.Entry> compareParamField;
            private FloatField compareValueFloatField;
            private IntegerField compareValueIntField;

            protected override void BuildUI() {
                conditionTypeField = new EnumField("切换条件");
                conditionTypeField.RegisterValueChangedCallback(evt => OnModify());
                conditionTypeField.Init(source.conditionType);

                exitTimeField = new FloatField("退出时间(%)");
                exitTimeField.SetSubFieldLeftPadding();
                exitTimeField.RegisterValueChangedCallback(evt => OnModify());
                exitTimeField.value = source.exitTime;

                paramTypeField = new EnumField("参数类型");
                paramTypeField.SetSubFieldLeftPadding();
                paramTypeField.RegisterValueChangedCallback(evt => OnModify());
                paramTypeField.Init(source.paramType);

                paramField = new PopupField<AGA_Blackboard.Entry>("blackboard");
                paramField.SetSubFieldLeftPadding();
                paramField.RegisterValueChangedCallback(evt => OnModify());

                compareOperatorField = new EnumField("比较方式");
                compareOperatorField.SetSubFieldLeftPadding();
                compareOperatorField.RegisterValueChangedCallback(evt => OnModify());
                compareOperatorField.Init(source.compareOperator);

                compareParamSourceField = new EnumField("用于比较的参数来源");
                compareParamSourceField.SetSubFieldLeftPadding();
                compareParamSourceField.RegisterValueChangedCallback(evt => OnModify());
                compareParamSourceField.Init(source.compareParamSource);

                compareParamField = new PopupField<AGA_Blackboard.Entry>("对比blackboard");
                compareParamField.SetSubFieldLeftPadding(2);
                compareParamField.RegisterValueChangedCallback(evt => OnModify());

                compareValueFloatField = new FloatField("对比值f");
                compareValueFloatField.SetSubFieldLeftPadding(2);
                compareValueFloatField.RegisterCallback<FocusOutEvent>(evt => OnModify());
                compareValueFloatField.value = source.compareValueFloat;

                compareValueIntField = new IntegerField("对比值i");
                compareValueIntField.SetSubFieldLeftPadding(2);
                compareValueIntField.RegisterCallback<FocusOutEvent>(evt => OnModify());
                compareValueIntField.value = source.compareValueInt;
            }
            private void OnModify(bool skipCallback = false) {
                source.conditionType = (ConditionType)conditionTypeField.value;
                source.exitTime = exitTimeField.value;
                source.paramKey = paramField.value.uuid;
                source.compareParamKey = compareParamField.value.uuid;
                source.compareValueInt = compareValueIntField.value;
                source.compareValueFloat = compareValueFloatField.value;
                source.compareParamSource = (AGAFieldModel_SMTransition.CompareParamSource)compareParamSourceField.value;
                source.paramType = (ConditionParameterType)paramTypeField.value;
                source.compareOperator = (CompareOperator)compareOperatorField.value;

                if (!skipCallback) {
                    inspectorChangeCallback?.Invoke();
                }
            }

            protected override void DrawUI() {
                Add(conditionTypeField);
                if (source.conditionType == ConditionType.ExitTime) {
                    Add(exitTimeField);
                } else {
                    Add(paramTypeField);
                    List<AGA_Blackboard.Entry> choice = null;
                    if (source.paramType == ConditionParameterType.Int) {
                        choice = ageContext.GetBlackboardEntriesInType(AGABlackboardType.Int);
                    } else if (source.paramType == ConditionParameterType.Float) {
                        choice = ageContext.GetBlackboardEntriesInType(AGABlackboardType.Float);
                    }
                    {
                        var selectIndex = choice.FindIndex(p => p.uuid == source.paramKey);
                        if (selectIndex < 0) {
                            selectIndex = 0;
                        }
                        paramField.choices = choice;
                        paramField.index = selectIndex;
                        paramField.formatListItemCallback = p => p.name; // 决定每个选项的文本
                        paramField.formatSelectedValueCallback = p => p.name; // 决定显示在下拉框中的文本
                    }
                    Add(paramField);
                    Add(compareOperatorField);
                    Add(compareParamSourceField);

                    if (source.compareParamSource == AGAFieldModel_SMTransition.CompareParamSource.Blackboard) {
                        var selectIndex = choice.FindIndex(p => p.uuid == source.compareParamKey);
                        if (selectIndex < 0) {
                            selectIndex = 0;
                        }
                        compareParamField.choices = choice;
                        compareParamField.index = selectIndex;
                        compareParamField.formatListItemCallback = p => p.name; // 决定每个选项的文本
                        compareParamField.formatSelectedValueCallback = p => p.name; // 决定显示在下拉框中的文本
                        Add(compareParamField);
                    } else if (source.paramType == ConditionParameterType.Int) {
                        Add(compareValueIntField);
                    } else {
                        Add(compareValueFloatField);
                    }
                }
                OnModify(true);
            }

        }
    }
}
